﻿// <copyright>
// Project: sofort.NET
// Date:  2014 - 02 - 04
// Copyright: Karl Haak 2014
// </copyright>
// <author>Karl Haak (www.karlhaak.de)</author>
namespace pay.sofort
{
    using System;
    using System.IO;
    using System.Net;
    using System.Text;
    using System.Xml.Linq;
    using Models;
    
    public class TPaySofortNotifyManager
    {
        #region ### Member ###

        private readonly TPaySofortConfig Config;
        private readonly PaySofortContext Context;

        #endregion

        #region ### Ctor ###

        public TPaySofortNotifyManager(TPaySofortConfig config)
        {
            Config = config;
            Context = new PaySofortContext(config.ConnectionString, config.Username);
        }

        #endregion

        #region ### process Part 1 (input) ###

        private PaySofortStatusNotfication ProcessNotification(string xmlIn, string status, string responseUrl)
        {
            // log in xml iunput 
            PaySofortIn paySofortIn = new PaySofortIn {Url = responseUrl, Payload = xmlIn}.SetNew(Config.Username);
            Context.PaySofortIn.Add(paySofortIn);
            Context.SaveChanges();

            // create object from XML and save
            PaySofortStatusNotfication statusNotfication = TPaySofortXml.CreatePaySofortStatusNotfication(xmlIn,
                Config.Username, responseUrl, status);
            Context.PaySofortStatusNotfication.Add(statusNotfication);
            Context.SaveChanges();

            return statusNotfication;
        }

        #endregion

        #region ### process Part 2 (query) ###

        private PaySofortOut StartOutLog(PaySofortTransactionRequest transactionRequest)
        {
            XDocument xDocument = TPaySofortXml.CreateXDocumentTransactionRequest(transactionRequest);
            string xmlText = xDocument.Declaration + Environment.NewLine + xDocument;

            PaySofortOut outLog = new PaySofortOut
            {
                RefGuid = transactionRequest.PaySofortTransactionRequestGuid,
                ApiKey = Config.ApiKey,
                Kundennummer = Config.Kundennummer,
                ProjectId = Config.ProjectId,
                Url = Config.SofortUeberweisungUrl,
                Typ = "Transaction_Request",
                PayloadOut = xmlText
            }.SetNew(Config.Username);

            Context.PaySofortOut.Add(outLog);
            Context.SaveChanges();
            return outLog;
        }

        private string RunWebRequestProvider(PaySofortOut outLog)
        {
            var Request = (HttpWebRequest) WebRequest.Create(Config.SofortUeberweisungUrl);
            Request.Method = "POST";
            Request.Credentials = new NetworkCredential(Config.Kundennummer, Config.ApiKey);
            Request.ContentType = "application/xml";
            Request.Accept = "application/xml; charset=UTF-8";

            // Set Payload
            byte[] requestBytes = new UTF8Encoding().GetBytes(outLog.PayloadOut);
            Stream stream = Request.GetRequestStream();
            stream.Write(requestBytes, 0, requestBytes.Length);
            stream.Close();

            // Read Response
            try
            {
                var response = (HttpWebResponse) Request.GetResponse();
                using (Stream responseStream = response.GetResponseStream())
                {
                    var sr = new StreamReader(responseStream);
                    string responsePayload = sr.ReadToEnd();
                    outLog.HttpStatus = response.StatusCode.ToString();
                    outLog.PayloadIn = responsePayload;
                    Context.SaveChanges();
                    return responsePayload; // return XML String from Provider
                }
            }
            catch (Exception ex)
            {
                outLog.PayloadIn = ex.Message;
                Context.SaveChanges();
                throw;
            }
        }

        private PaySofortTransaction GetTransactionFromProvider(string transaction_key)
        {
            // Create and Save Transaction_Request
            PaySofortTransactionRequest transactionRequest =
                new PaySofortTransactionRequest {transaction_key = transaction_key}.SetNew(Config.Username);
            Context.PaySofortTransactionRequest.Add(transactionRequest);
            Context.SaveChanges();

            // Create OutLog
            PaySofortOut outLog = StartOutLog(transactionRequest);

            // Send Transaction_Request
            string xmlIn = RunWebRequestProvider(outLog);

            // Create and Save Transaction
            PaySofortTransaction transaction = TPaySofortXml.CreateTransaction(xmlIn, Config);
            Context.PaySofortTransaction.Add(transaction);
            Context.SaveChanges();
            return transaction;
        }

        #endregion

        #region ### public ###

        public PaySofortTransaction ProcessPaySofortNotify(string xmlIn, string status, string responseUrl)
        {
            PaySofortStatusNotfication statusNotfication = ProcessNotification(xmlIn, status, responseUrl);

            PaySofortTransaction transaction = GetTransactionFromProvider(statusNotfication.transaction_key);

            return transaction;
        }

        #endregion
    }
}